<template>
    <div 
        class="context-menu" 
        ref="contextMenuRef"
    >
        <!-- 限制上传的主体区域，在哪里可以触发 -->
        <slot/>
        <!-- 右键菜单 -->
        <Teleport to="body">
            <!-- 过度组件内置事件，获取内部最外层元素 -->
            <Transition @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter">
                <template v-if="menu.length">
                    <div ref="menuRef" class="menu" v-if="isShow">
                        <ul >
                            <li v-for="(item, index) in menu" :key="index" @click="item.click">
                                {{ item.label }}
                            </li>
                        </ul>
                    </div>
                </template>
                <template v-else>
                    <div ref="menuRef" class="menu" v-if="isShow">
                        <slot name="overlay"/>
                    </div>
                </template>
            </Transition>
        </Teleport>
    </div>
</template>

<script setup lang="ts">
import type { ContextMenuItem } from './types';
import { useContextMenu } from './hooks/useContextMenu';
import { computed, nextTick, ref } from 'vue';

const props = withDefaults(defineProps<{
    menu?: ContextMenuItem[]
}>(), {
    menu:()=>[]
})

const contextMenuRef = ref<HTMLElement>();
const menuRef = ref<HTMLElement>();
const saveX = ref(0)
const saveY = ref(0)

const { x, y, isShow } = useContextMenu(contextMenuRef)

const handleBeforeEnter = (el: Element) => {
    // @ts-ignore
    el.style.height = "0";
}
const handleEnter = (el: Element) => {
    // @ts-ignore
    el.style.height = 'auto'; // 高度设置auto以适应内容
    const h = el.clientHeight // 触发浏览器重新计算高度 ,拿到最终高度

    const contextMenuRect = contextMenuRef.value?.getBoundingClientRect()

    const relativeX = x.value + el.clientWidth
    const relativeY = y.value + el.clientHeight
    
    saveX.value = x.value
    saveY.value = y.value

    // 判断是否超出容器右边界
    const leftOrRight = relativeX > (contextMenuRect.width + contextMenuRect?.x) ? "right" : "left"
    // 判断是否超出容器下边界
    const topOrBottom = relativeY > (contextMenuRect.height + contextMenuRect?.y) ? "bottom" : "top"

    el.style['top'] = topOrBottom === "top" ? y.value + 'px' : y.value  -  el.clientHeight + 'px'
    el.style['left'] = leftOrRight === "left" ? x.value + 'px' : x.value -  el.clientWidth + 'px'

    // @ts-ignore
    el.style.height = "0"; // 先设置为0高度，触发过渡效果
    requestAnimationFrame(() => {
        // @ts-ignore
        el.style.height = `${h}px`; // 设置高度为实际内容高度
        // @ts-ignore
        el.style.transition = 'height 0.3s ease'; // 添加过渡效果
    })
}

const handleAfterEnter = (el: Element) => {
    // 处理点击菜单项需要等待过度接受后触发问题
    // @ts-ignore
    el.style.transition = ""
}

defineExpose({
    x:saveX,
    y:saveY
})
</script>

<style lang='scss' scoped>
.context-menu {

}
.menu {
    position: fixed;
    background-color: #f9f9f9;
    /* 背景色稍微偏灰，与纯白色区分 */
    border: 1px solid #eaeaea;
    /* 添加浅灰色边框，增加层次感 */
    text-align: center;
    z-index: 99999;
    border-radius: 5px;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    ul{
        margin:0!important;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }

    /* 添加阴影，提升立体感 */
    li {
        width: 100%;
        padding: 8px 12px;
        /* 增加内边距，让菜单项看起来更宽敞 */
        cursor: pointer;

        &:hover {
            background-color: #e0f7fa;
            /* 悬停时背景色偏蓝色 */
        }
    }
}
</style>